#include <iostream>
using namespace std;

const int N = 1e5 + 10; //最大人数1e5

//每个节点的父亲节点
int fa[N]; 

//初始化
void init(){
    for(int i = 0; i < N; i++){
        fa[i] = i;
    }
}

//并查集查找父亲节点的函数
int find(int x)
{
    if (x != fa[x])
        fa[x] = find(fa[x]); //路径压缩过程
    return fa[x];
}

void merger(int a, int b){
    //b的顶级双亲 设为 a的顶级双亲的双亲
    fa[find(a)] = find(b);
}

//表示两人
struct node
{
    int x, y;
}e[N];

int main()
{
    int n, a, b, c, k = 0; // k记录有矛盾的边
    scanf("%d", &n);
    // for (int i = 1; i <= n; i++)
    //     fa[i] = i;
    init();
    for (int i = 1; i <= n; i++)
    {
        scanf("%d %d %d", &a, &b, &c);
        
        if (c == 1) //两人要在同一队
        {
            // a = find(a), b = find(b); //查找父亲节点
            // if (a != b)
            //     fa[a] = b; //若父亲节点不相同，就合并成一个集合
            merger(a, b);
        }
        else
            e[k++] = {a, b}; //矛盾关系存起来
    }
    
    bool f = true;
    //判断矛盾
    for (int i = 0; i < k; i++)
    {  
        int pa = find(e[i].x), pb = find(e[i].y);
        if (pa == pb)   //有矛盾的两人在同一队
        {
            f = false;
            break;
        }
    }
    if (f)
        puts("YES");
    else
        puts("NO");
    return 0;
}

/*

题目描述
有n个同学想要组队，但是这些同学之间存在一些矛盾或者是要好关系。若两个同学关系要好，那么他们必须要在一队中；
若两个同学之间有矛盾，那么他们两个必然不可以在一队；若没有矛盾也不要好的同学，他们可以随意分配。
换言之，就是判断分组时可以把有矛盾的同学分开，关系友好的同学都分在一组。

现在由小A来分配组队，请你帮帮他，来判断一下这些人是否可以成功组队，若组队成功，则输出”YES”，反之输出“NO”。


输入格式
第一行包含一个正整数 n，表示该需要组队的人数。

以下 n行每行包含3 个整数 ai，bi，xi，描述一对同学之间的关系，相邻整数之间用单个空格隔开。若xi=1，
则表示ai和bi关系友好，若xi=0，则表示ai和bi有矛盾。

输出格式
输出YES或者NO。YES 表示这一组同学可以成功组队，NO表示不可成功组队。

数据范围
1 ≤ n ≤ 100000,

1 ≤ ai，bi ≤ n，对于任何一个i，满足ai不等于bi，并且对于任意两个人，他们之间不会既存在矛盾，也关系友好，

0≤ xi≤ 1

样例1
输入数据 1
3
1 2 1
2 3 1
1 3 0
输出数据 1
NO

*/